/******************************************************************************
 * * call_log_main.c - implementation of call log main functions
 *
 * *(C) Copyright 2019 Asr International Ltd.
 * * All Rights Reserved
 * ******************************************************************************/

#include "call_log_global.h"

/**********************
* GLOBAL VARIABLES
**********************/
Call_Log_Mng_t g_Call_Log_Mng;

/**
 * set block state
 * param BlockId: block ID
 * param state: 1: allocated, 0: free
 * return VOID
 */
VOID Block_Set_State(UINT16 BlockId, UINT8 state)
{
    if (1 == state) /* allocated */
    {
        g_Call_Log_Mng.BlockBitmap[BlockId / 8] |= (0x80 >> (BlockId % 8));
    }
    else /* free */
    {
        g_Call_Log_Mng.BlockBitmap[BlockId / 8] &= ~(0x80 >> (BlockId % 8));
    }

    // printf("BlockId=%d, state=%d in Block_Set_State\n", BlockId, state);
}

/**
 * allocate block
 * return block ID
 */
INT16 Block_Alloc(VOID)
{
    INT16  BlockId = -1;
    UINT16 i       = 0;
    UINT16 j       = 0;

    for (i = 0; i <= NV_CALL_LOG_MAX_NUM / 8; i++)
    {
        for (j = 0; j < 8; j++)
        {
            if ((i == NV_CALL_LOG_MAX_NUM / 8) && (j == NV_CALL_LOG_MAX_NUM % 8))
            {
                // no free block
                BlockId = -1;
                break;
            }

            if (0 == ((g_Call_Log_Mng.BlockBitmap[i] << j) & 0x80))
            {
                // find free block, set bitmap to 1
                BlockId = (i * 8 + j);
                Block_Set_State(BlockId, 1);
                return(BlockId);
            }
        }
    }

    return(BlockId);
}

/**
 * free block
 * param BlockId: block ID
 * return VOID
 */
VOID Block_Free(UINT16 BlockId)
{
    Block_Set_State(BlockId, 0);
}

/**
 * add call log into list
 * param Data: NV_Call_Log_Data_t *
 * return Call_Log_Node_t *
 */
Call_Log_Node_t *Call_Log_Add(NV_Call_Log_Data_t *Data)
{
    Call_Log_Node_t *CallLogNew  = NULL;
    Call_Log_Node_t *CallLogNext = NULL;

    CallLogNext = _lv_ll_get_head(&g_Call_Log_Mng.CallLogList);
    if (NULL == CallLogNext)
    {
        CallLogNew = _lv_ll_ins_head(&g_Call_Log_Mng.CallLogList);
    }
    else
    {
        // sort by timestamp descendingly
        while (CallLogNext)
        {
            if (Data->Timestamp >= CallLogNext->Data.Timestamp)
            {
                CallLogNew = _lv_ll_ins_prev(&g_Call_Log_Mng.CallLogList, CallLogNext);
                break;
            }
            CallLogNext = _lv_ll_get_next(&g_Call_Log_Mng.CallLogList, CallLogNext);
        }

        if (NULL == CallLogNext)
        {
            CallLogNew = _lv_ll_ins_tail(&g_Call_Log_Mng.CallLogList);
        }
    }

    memcpy(&CallLogNew->Data, Data, sizeof(NV_Call_Log_Data_t));

    return(CallLogNew);
}

/**
 * change call log count
 * param Type: CALL_LOG_TYPE
 * param var: INT16
 * return VOID
 */
VOID Call_Log_Update_Cnt(CALL_LOG_TYPE Type, INT16 var)
{
    switch (Type)
    {
    case CALL_LOG_TYPE_MISSED:
        g_Call_Log_Mng.MissedCalls += var;
        break;

    case CALL_LOG_TYPE_RECEIVED:
        g_Call_Log_Mng.ReceivedCalls += var;
        break;

    case CALL_LOG_TYPE_DIALLED:
        g_Call_Log_Mng.DialledCalls += var;
        break;

    default:
        printf("unknown call log type (%d) in Call_Log_Update_Cnt\n", Type);
        break;
    }
}

/**
 * get call log count
 * param Type: CALL_LOG_TYPE
 * return UINT16
 */
UINT16 Call_Log_Get_Cnt(CALL_LOG_TYPE Type)
{
    UINT16 CallCnt = 0;

    switch (Type)
    {
    case CALL_LOG_TYPE_MISSED:
        CallCnt = g_Call_Log_Mng.MissedCalls;
        break;

    case CALL_LOG_TYPE_RECEIVED:
        CallCnt = g_Call_Log_Mng.ReceivedCalls;
        break;

    case CALL_LOG_TYPE_DIALLED:
        CallCnt = g_Call_Log_Mng.DialledCalls;
        break;

    case CALL_LOG_TYPE_ALL:
        CallCnt = g_Call_Log_Mng.MissedCalls + g_Call_Log_Mng.ReceivedCalls + g_Call_Log_Mng.DialledCalls;
        break;

    default:
        break;
    }

    return(CallCnt);
}

/**
 * entry of call log APP
 */
VOID Call_Log_Main(VOID)
{
    Display_Call_Log_Menu();
}

/**
 * call log event handler
 */
VOID Call_Log_Event_Handle()
{
    // event and message dispatch
}
